#!/usr/bin/env python2
#
# n-snakes: Multidimentional, procedural exploration game.
# http://code.google.com/p/n-snakes/
#
#
# Copyright (c) 2012 Eliot Eshelman
#
# Built upon Snakes demo written by Jessica McKellar for OpenHatch
# https://openhatch.org/wiki/Snakes_Pygame
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
###############################################################################


import pygame
import random
import sys

from objects.snake import Snake
from objects.food import Food

GAME_WIDTH = 1024
GAME_HEIGHT = 768
BACKGROUND_COLOR = (0x00, 0x00, 0x00)
FRAMERATE = 32
ARROW_KEYS = (pygame.K_UP, pygame.K_DOWN, pygame.K_LEFT, pygame.K_RIGHT)

game_surface = None


def initialize_screen():
    # Initialize the screen and game objects.
    pygame.init()
    pygame.display.set_caption('N-Snakes - Press <Esc> to Quit, <Space> to Restart')
    pygame.key.set_repeat(10,50)

    return pygame.display.set_mode((GAME_WIDTH, GAME_HEIGHT))


def move_bad_snake(bad_snake, game_surface, current_direction):
    bad_snake.move(current_direction, game_surface)

    new_direction = None
    if random.random() > .75:
        while new_direction == None or new_direction == current_direction:
            new_direction = random.choice(ARROW_KEYS)
        current_direction = new_direction

    return current_direction


def detect_collisions(good_snake, bad_snake):
    """
    Detect collisions between the snakes (and themselves).

    Returns two boolean values:
    [0] Did good_snake collide with anything?
    [1] Did bad_snake collide with anything?
    """
    collision_good = False
    collision_bad = False

    # Check if good snake has died (head collisions)
    if good_snake.head_hit_body() or pygame.sprite.spritecollideany(
            good_snake.get_head(), bad_snake.get_all_segments()
        ):
                collision_good = True

    # Check if bad snake has died (head collisions)
    if bad_snake.head_hit_body() or pygame.sprite.spritecollideany(
            bad_snake.get_head(), good_snake.get_all_segments()
        ):
                collision_bad = True

    return collision_good, collision_bad


def respawn_bad_snake():
    global game_surface, bad_snake, bad_snake_direction

    bad_snake = Snake(pygame.Color(0xff, 0x00, 0x00), 2,
                      [random.randint(0, GAME_WIDTH),
                       random.randint(0, GAME_HEIGHT)])
    bad_snake_direction = random.choice(ARROW_KEYS)


def create_food(food, game_surface):
    while len(food) < 50:
        food.add(Food(game_surface.get_rect()))


def play_game():
    global game_surface, bad_snake, bad_snake_direction

    # Create game surface with solid background.
    game_surface = initialize_screen()
    background = pygame.Surface(game_surface.get_size())
    background.fill(BACKGROUND_COLOR)
    game_surface.blit(background, (0, 0))
    pygame.display.update()

    # Create our snake.
    good_snake = Snake(pygame.Color(0xff, 0xff, 0xff), 2,
                       [random.randint(0, GAME_WIDTH),
                        random.randint(0, GAME_HEIGHT)])

    # Create the bad snake.
    bad_snake = None
    respawn_bad_snake()

    snake_food = pygame.sprite.RenderUpdates()
    create_food(snake_food, game_surface)

    game_clock = pygame.time.Clock()
    while True:
        game_clock.tick(FRAMERATE)

        # Keep track of screen areas which need to be re-drawn
        dirty_rects = []

        # Detect and respond to user keypresses.
        for e in pygame.event.get():
            if e.type == pygame.QUIT:
                terminate()
                return False
            elif e.type == pygame.KEYDOWN:
                if e.key == pygame.K_ESCAPE:
                    terminate()
                    return False
                elif e.key in ARROW_KEYS:
                    good_snake.move(e.key, game_surface)

        # Move the bad snake.
        bad_snake_direction = move_bad_snake(bad_snake, game_surface,
                                             bad_snake_direction)

        # Detect snake collisions.
        good, bad = detect_collisions(good_snake, bad_snake)
        if good:
            return restart(game_surface)
        elif bad:
            bad_snake.die()
            dirty_rects += bad_snake.draw(game_surface)
            respawn_bad_snake()

        # Have both snakes eat any available food.
        good_snake.try_to_eat(snake_food)
        bad_snake.try_to_eat(snake_food)

        # Refresh the food supply.
        create_food(snake_food, game_surface)

        # Update the snake and food sprites.
        good_snake.update()
        bad_snake.update()
        snake_food.update()

        # Draw sprites and track updates.
        dirty_rects += snake_food.draw(game_surface)
        dirty_rects += good_snake.draw(game_surface)
        dirty_rects += bad_snake.draw(game_surface)
        
        # Update screen
        pygame.display.update(dirty_rects)

        # Clear old sprite positions before the next loop
        snake_food.clear(game_surface, background)
        good_snake.clear(game_surface, background)
        bad_snake.clear(game_surface, background)


def restart(game_surface):
    """
    Display a GAME OVER screen and return True if a new game should be
    started or False if the user wants to quit.
    """
    # Clear the background.
    game_surface.fill(BACKGROUND_COLOR)

    # Draw the game over message.
    text = 'GAME OVER'
    font = pygame.font.SysFont('Tahoma', 128)
    line = font.render(text, True, (20, 20, 220))

    x_center = (GAME_WIDTH / 2) - (line.get_width() / 2)
    y_center = (GAME_HEIGHT / 2) - (line.get_height() / 2)

    game_surface.blit(line, line.get_rect().move((x_center, y_center)))
    pygame.display.update()

    # Wait for the user to either restart or quit.
    while True:
        for e in pygame.event.get():
            if e.type == pygame.QUIT:
                terminate()
                return False
            elif e.type == pygame.KEYDOWN:
                if e.key == pygame.K_ESCAPE:
                    terminate()
                    return False
                elif e.key == pygame.K_SPACE:
                    return True


def terminate():
    pygame.quit()
    sys.exit()


if __name__ == '__main__':
    still_playing = True
    while still_playing:
        still_playing = play_game()
